#缓冲区，F区停车区分配，F区路网构建；
#stop-position 无效；
#全局变量梳理；
#路网坐标与孪生坐标匹配。
# vehicle_load_after_restart_simulation：
# 1）stop for vehicle 'T743' on lane 'r14-6Tr15-6_0' has an invalid position.
# 2）Unknown edge 's2-786Ts2-677' in route.
# Unknown edge 's2-786Ts2-677' in route.
# 2025-03-19 23:05:55.410 | INFO     | __main__:<module>:42 - 启动仿真时发生错误: Unknown edge 's2-786Ts2-677' in route.
# traci.exceptions.TraCIException: Unknown edge 's2-786Ts2-677' in route.


# File Name： dt
# Description :
# Author : ‘Xuegen Wang’
# create_date： 2025/3/6
# Change Activity: 修改任务更新代码


import os
import copy
import json
import time
from datetime import datetime, timedelta
import traci
import random
from loguru import logger
import subprocess
import shutil
import glob
import traci.constants as tc
import traceback

import netxml
import routepy


ADDED_RANGES = {}
ADDED_JUNCTIONS = set()
VESSEL2LANE = {}
TRUCK_EXISTS_SET = set()   # 存储、维护路网中所有车辆，包括长期停在停车区中的
TRUCK_SUBSCRIBED_SET = set()  #存储、维护路网中所有作业车辆，暂时不用。traci.vehicle.getIDList() = TRUCK_SUBSCRIBED_SET + TRUCK_UNSUBSCRIBED_SET
TRUCK_UNSUBSCRIBED_SET = set()  #存储、维护路网中不输出坐标等信息给Digital Twin(DT)、无作业任务的车辆，可以直接调用setRoute()
VEHICLE_TO_STOP_COORD = {}  #用于存储APPEND_STOP_LIST中随机选择的停车点信息
ADDED_UPDATED_VEHICLE_ID_EDGE = {}



def append_rest_stop_to_vehicle(ROUTE_FILE, vehicle_id, configs):
    """
    主要用于无vessel_id等属性的车辆从现有位置驶向休息区
    :param ROUTE_FILE: 
    :param vehicle_id: 
    :return: 
    """""
    global APPEND_STOP_LIST, VEHICLE_TO_STOP_COORD, TRUCK_SUBSCRIBED_SET,TRUCK_UNSUBSCRIBED_SET, ADDED_UPDATED_VEHICLE_ID_EDGE
    if vehicle_id not in ADDED_UPDATED_VEHICLE_ID_EDGE:
        current_edge = routepy.get_edge_from_rouxml(ROUTE_FILE, vehicle_id)
    elif vehicle_id in ADDED_UPDATED_VEHICLE_ID_EDGE:
        current_edge = ADDED_UPDATED_VEHICLE_ID_EDGE[vehicle_id]
    else:
        current_edge = traci.vehicle.getRoadID(vehicle_id)
        if current_edge is None or current_edge == "":
            current_edge = random.choice(routepy.extract_route_edges_from_file(ROUTE_FILENAME))

    random_stop_temp = random.choice(APPEND_STOP_LIST)
    APPEND_STOP_LIST.remove(random_stop_temp)
    VEHICLE_TO_STOP_COORD[vehicle_id] = random_stop_temp
    rest_stop_edge = random_stop_temp['lane'][:-2]
    lane_index = 0
    lane_pos = 5
    lane_length = traci.lane.getLength(random_stop_temp['lane'])
    if lane_pos > lane_length:
        lane_pos = lane_length
    rest_route = traci.simulation.findRoute(current_edge, rest_stop_edge)
    traci.vehicle.setRoute(vehicle_id, rest_route.edges)
    traci.vehicle.setStop(vehID=vehicle_id, edgeID=rest_stop_edge, laneIndex=lane_index, pos=lane_pos, duration=configs.TRUCK_STOP_TIME)

    traci.vehicle.subscribe(vehicle_id, [
        tc.VAR_POSITION,
        tc.VAR_ANGLE,
        tc.VAR_SPEED,
        tc.VAR_ROAD_ID,
        tc.VAR_LANE_INDEX,
        tc.VAR_LANE_ID,
        tc.VAR_LANEPOSITION
    ])
    TRUCK_SUBSCRIBED_SET.add(vehicle_id)


def redis_task_data_manager(task_data, configs, vehicle_id=None):
    if task_data:
        if vehicle_id is not None:
            # configs.redis_conn.hset('tk_data', vehicle_id, json.dumps(task_data))
            logger.warning(f"集卡{vehicle_id}将驶向停车区，因为其vessel_id不存在！")
        if vehicle_id is None:
            # configs.redis_conn.hset("tk_data", mapping=task_data)
            logger.warning(f"标志3：向孪生发送{len(task_data)}辆车坐标信息。")

def vehicle_task_check(vehicle_id,task_info,simulation_time, configs):
    """
    主要用于清理无效（无vessel_id, 坐标为空）集卡作业数据：通过发送"stop_exist": 0告知redis中task_data管理者删除集卡vehicle_id的无效作业数据
    """""
    global VESSEL2LANE, ROUTE_FILENAME,TRUCK_UNSUBSCRIBED_SET
    check_vessel_id = task_info["vessel_id"]
    if check_vessel_id not in VESSEL2LANE.keys():

        if vehicle_id not in traci.vehicle.getLoadedIDList():
            current_pos = traci.vehicle.getPosition(vehicle_id)
            angle = traci.vehicle.getAngle(vehicle_id)
        else:
            current_pos = traci.vehicle.getPosition(vehicle_id)
            angle = traci.vehicle.getAngle(vehicle_id)
        vehicle_tk_data = {
            "truck_id": vehicle_id,
            "task_id": task_info["task_id"],
            "simulation_start": configs.SIMULATION_START,
            "simulation_time": simulation_time,
            "current_pos": current_pos,
            "angle": (angle-90) % 360,
            "stop_exist": 0
        }

        append_rest_stop_to_vehicle(ROUTE_FILENAME, vehicle_id, configs)
        # time_to_flag3 = time.time() - start_time
        # logger.info(f"时间到标志3: {time_to_flag3:.4f} 秒")
        redis_task_data_manager(vehicle_tk_data, configs, vehicle_id)

        return False
    elif len(task_info["stop_coord"]) >= 1:
        return True


def set_vehicle_route_and_stop(vehicle_id, task_info, configs):
    global VESSEL2LANE, APPEND_STOP_LIST, ROUTE_FILENAME, VEHICLE_TO_STOP_COORD,TRUCK_UNSUBSCRIBED_SET, TRUCK_SUBSCRIBED_SET, ADDED_UPDATED_VEHICLE_ID_EDGE
    try:
        if vehicle_id not in ADDED_UPDATED_VEHICLE_ID_EDGE:
            current_edge = routepy.get_edge_from_rouxml(ROUTE_FILENAME, vehicle_id)  # 从rou.xml中获取边信息
        elif vehicle_id in ADDED_UPDATED_VEHICLE_ID_EDGE:
            current_edge = ADDED_UPDATED_VEHICLE_ID_EDGE[vehicle_id]
        else:
            current_edge = traci.vehicle.getRoadID(vehicle_id)
            if current_edge is None or current_edge == "":
                current_edge = "-r10-2Tr11-2"

        stop_coords = task_info["stop_coord"]
        route_edges = []
        temp_stop = random.choice(APPEND_STOP_LIST)
        APPEND_STOP_LIST.remove(temp_stop)
        VEHICLE_TO_STOP_COORD[vehicle_id] = temp_stop
        stop_coords.append(temp_stop)
        # 设置路由
        for stop in stop_coords:
            lane_type = stop.get("type")
            if lane_type == "yard":
                stop_edge = stop.get("lane")[:-2]
            elif lane_type == "qc":
                sumo_stop_lane_index = int(stop.get("lane")[-1])
                vessel_id = task_info["vessel_id"]
                stop_lane = VESSEL2LANE[vessel_id]['dtlane2sumolane'][sumo_stop_lane_index]
                stop_edge = stop_lane[:-2]
            elif lane_type == "rest":
                stop_edge = stop.get("lane")[:-2]
            route = traci.simulation.findRoute(current_edge, stop_edge)

            if route.edges:
                if len(route_edges) == 0:
                    route_edges.extend(list(route.edges))
                else:
                    route_edges.pop()
                    route_edges.extend(list(route.edges))
                current_edge = route.edges[-1]
            else:
                logger.info(f"集卡{vehicle_id}没有找到去 {stop_edge} 的路径，请检查路网是否正确。")
                logger.error(traceback.format_exc())
                return False
        tuple_route_edges = tuple(route_edges)

        if route_edges:
            tuple_route_edges = tuple(route_edges)
            traci.vehicle.setRoute(vehicle_id, tuple_route_edges)

        traci.vehicle.setRoute(vehicle_id, tuple_route_edges)

        # 设置停车点
        direction = VESSEL2LANE[vessel_id]["direction"]
        for stop in stop_coords:
            stop_x, stop_y = stop["coord"]
            lane_type = stop.get("type")
            lane = stop["lane"]
            worktime = float(stop["worktime"])
            lane_index = int(lane[-1])
            lane_length = 0

            if lane_type == "qc":
                lane_temp = VESSEL2LANE[vessel_id]["dtlane2sumolane"][lane_index]
                stop_edge = lane_temp[:-2]
                lane_id = int(lane_temp[-1])
                lane_length = traci.lane.getLength(lane_temp)
                if direction == "right":
                    lane_pos = abs(stop_x - VESSEL2LANE[vessel_id]["start_x"])
                elif direction == "left":
                    lane_pos = abs(VESSEL2LANE[vessel_id]["start_x"] - stop_x)

            elif lane_type == "yard":
                stop_edge = lane[:-2]
                lane_id = lane_index
                lane_length = traci.lane.getLength(lane)
                if lane[0] == "-": # 负向
                    stop_edge = stop_edge[1:]
                    junction_id_from = stop_edge.split("T")[1]
                    x_from, y_from = traci.junction.getPosition(junction_id_from)
                    lane_pos = abs(x_from - stop_x)
                else:
                    junction_id_from = stop_edge.split("T")[0]
                    x_from, y_from = traci.junction.getPosition(junction_id_from)
                    lane_pos = abs(stop_x - x_from)

            elif lane_type == "rest":
                stop_edge = lane[:-2]
                lane_id = lane_index
                lane_length = traci.lane.getLength(lane)
                if lane[0] == "-":
                    stop_edge_temp = stop_edge[1:]
                    junction_id_from = stop_edge_temp.split("T")[0]
                    junction_id_to = stop_edge.split("T")[1]
                    x_from, y_from = traci.junction.getPosition(junction_id_from)
                    x_to, y_to = traci.junction.getPosition(junction_id_to)
                    if abs(y_from - y_to) < 1 and abs(x_from - x_to) > 1:
                        lane_pos = abs(stop_x - x_from)
                    elif abs(x_from - x_to) < 1 and abs(y_from - y_to) > 1:
                        lane_pos = abs(stop_y - y_from)
                else:
                    junction_id_from = stop_edge.split("T")[0]
                    junction_id_to = stop_edge.split("T")[1]
                    x_from, y_from = traci.junction.getPosition(junction_id_from)
                    x_to, y_to = traci.junction.getPosition(junction_id_to)
                    if abs(y_from - y_to) < 1 and abs(x_from - x_to) > 1:
                        lane_pos = abs(stop_x - x_from)
                    elif abs(x_from - x_to) < 1 and abs(y_from - y_to) > 1:
                        lane_pos = abs(stop_y - y_from)

            if lane_pos > lane_length:
                lane_pos = lane_length
            traci.vehicle.setStop(vehID=vehicle_id, edgeID=stop_edge, laneIndex=lane_id, pos=lane_pos, duration=worktime)

        # 添加订阅
        traci.vehicle.subscribe(vehicle_id, [
            tc.VAR_POSITION,
            tc.VAR_ANGLE,
            tc.VAR_SPEED,
            tc.VAR_ROAD_ID,
            tc.VAR_LANE_INDEX,
            tc.VAR_LANE_ID,
            tc.VAR_LANEPOSITION
        ])
        TRUCK_SUBSCRIBED_SET.add(vehicle_id)
        if vehicle_id in TRUCK_UNSUBSCRIBED_SET:
            TRUCK_UNSUBSCRIBED_SET.remove(vehicle_id)

    except Exception as e:
        logger.info(f"设置车辆 {vehicle_id} 的任务时发生错误: {e}")
        logger.info(traceback.format_exc())
        return False


# 重启仿真函数
def restart_simulation(net_file,configs):
    try:
        logger.info("关闭当前仿真会话...")
        traci.close()
        logger.info(f"启动新的仿真会话，使用新路网文件: {net_file}")
        traci.start([configs.sumoBinary, "-c", "dt.sumocfg"])
    except Exception as e:
        logger.error(f"启动仿真时发生错误: {e}")


def clean_temp_files():
    for file in glob.glob("*.rou.xml"):
        if os.path.basename(file) == "type.rou.xml":
            continue
        os.remove(file)

    for file in glob.glob("net\\*.net.xml"):
        if len(os.path.basename(file)) > 16:  #####!!!要初始化源文件,if file != network:
            os.remove(file)
    # 清理 net/net_with_id 文件夹下的 .net.xml 文件
    for file in glob.glob("net\\net_with_id\\*.net.xml"):
        if len(os.path.basename(file)) > 16:  #####!!!要初始化源文件,if file != network:
            os.remove(file)

def initialize_netxml(vessel_data, configs):
    global ADDED_JUNCTIONS, ADDED_RANGES, VESSEL2LANE
    i = 0
    intermediate_files = []  # 用于存储中间生成的文件名

    for vessel, vessel_info in vessel_data.items():
        vessel_id = vessel
        st_x = vessel_info.get("tail_x", None)
        ed_x = vessel_info.get("head_x", None)
        if i != 0:
            net_file_name = netxml.add_netxml(net_file_name, vessel_id, st_x, ed_x, ADDED_JUNCTIONS, ADDED_RANGES,
                                              VESSEL2LANE)
            intermediate_files.append(net_file_name)  # 记录中间生成的文件
        else:
            net_file_name = netxml.add_netxml(configs.BASE_NET_FILE, vessel_id, st_x, ed_x, ADDED_JUNCTIONS,
                                              ADDED_RANGES, VESSEL2LANE)
            intermediate_files.append(net_file_name)  # 记录中间生成的文件
        i += 1

    # 创建目标文件夹
    if not os.path.exists('net\\net_with_id'):
        os.makedirs('net\\net_with_id')

    # 清理中间生成的文件
    for temp_file in intermediate_files[:-1]:  # 排除最后一个文件（最终文件）
        if os.path.exists(temp_file):
            os.remove(temp_file)

    # 复制并重命名最终生成的文件到 net_with_id 文件夹
    target_filename = os.path.basename(net_file_name).replace('.net.xml', '_id.net.xml')
    target_file_path = os.path.join('net\\net_with_id', target_filename)
    shutil.copy(net_file_name, target_file_path)

    # 返回原始文件路径和备份文件路径
    return net_file_name, target_file_path


def update_netxml(NET_FILENAME, vessel_data, NET_FILENAME_ID):
    global ADDED_JUNCTIONS
    global ADDED_RANGES
    global VESSEL2LANE
    NET_FILENAME_TEMP = os.path.basename(NET_FILENAME)
    str1 = NET_FILENAME_TEMP.split('.')[0]
    str2 = str1[9:]
    old_vessel_list = str2.split('-')

    old_keys = set(old_vessel_list)
    new_keys = set(vessel_data.keys())

    ##处理更新后船舶数量与原船舶数量一致的情况
    filename_before_added = None
    same_keys = old_keys & new_keys
    deleted_same_number_vessel_id = old_keys - same_keys
    added_same_number_vessel_id = new_keys - same_keys
    added_same_number_vessel_dict = {}
    deleted_same_number_vessel_list = list(deleted_same_number_vessel_id)
    if len(new_keys) == len(old_keys):
        for key in added_same_number_vessel_id:
            added_same_number_vessel_dict[key] = vessel_data[key]

    if len(new_keys) == len(old_keys):
        filename_after_delete = netxml.delete_netxml(NET_FILENAME_ID, deleted_same_number_vessel_list, ADDED_JUNCTIONS, ADDED_RANGES,
                                               VESSEL2LANE)

        for vessel_id, vessel_info in added_same_number_vessel_dict.items():
            st_x, ed_x = vessel_info.get("tail_x", None), vessel_info.get("head_x", None)
            filename_before_added = netxml.add_netxml_vessel_data_change(filename_after_delete, vessel_id, st_x, ed_x, ADDED_JUNCTIONS, ADDED_RANGES,
                                                VESSEL2LANE)

    ##处理更新后船舶数量与原船舶数量不一致的情况
    add_vessel_dict = {}
    add_vessels_id = new_keys-old_keys
    delete_vessels_id = old_keys - new_keys
    delete_vessel_list = list(delete_vessels_id)
    if len(add_vessels_id) > 0:
        for key in add_vessels_id:
            add_vessel_dict[key] = vessel_data[key]

    if len(delete_vessel_list) > 0:
        filename_before = netxml.delete_netxml(NET_FILENAME_ID, delete_vessel_list, ADDED_JUNCTIONS, ADDED_RANGES, VESSEL2LANE)
    else:
        filename_before_needed_add = NET_FILENAME_ID
    for vessel_id, vessel_info in add_vessel_dict.items():
        st_x, ed_x = vessel_info.get("tail_x", None), vessel_info.get("head_x", None)
        filename_before = netxml.add_netxml_vessel_data_change(filename_before_needed_add, vessel_id, st_x, ed_x,  ADDED_JUNCTIONS, ADDED_RANGES, VESSEL2LANE)

    if filename_before_added:
        filename_before = filename_before_added

    return filename_before


def update_vehicle_tasks(need_update_task:dict, need_add_task:dict, simulation_time, configs):
    global VESSEL2LANE
    global ROUTE_FILENAME
    global APPEND_STOP_LIST
    global VEHICLE_TO_STOP_COORD
    global ADDED_UPDATED_VEHICLE_ID_EDGE
    global TRUCK_UNSUBSCRIBED_SET
    global TRUCK_START_LIST
    converter = routepy.NetworkConverter(configs.BASE_NET_FILE)

    if len(need_add_task)>0:
        logger.info(f"添加集卡车辆及任务")
        for vehicle_id in need_add_task.keys(): # 添加新车辆
            TRUCK_START_LIST = routepy.get_all_car_start_coordinates(configs.BASE_NET_FILE, configs.truck_start_type)
            random_truck_start_list = random.choice(TRUCK_START_LIST)
            x, y = random_truck_start_list
            edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)

            if edge_id is None or lane_pos is None or edge_id == "":
                random_truck_start_list = random.choice(TRUCK_START_LIST)
                x, y = random_truck_start_list
                edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
                if edge_id is None or lane_pos is None or edge_id == "":
                    random_truck_start_list = random.choice(TRUCK_START_LIST)
                    x, y = random_truck_start_list
                    edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
                    if edge_id is None or lane_pos is None or edge_id == "":
                        edge_id = random.choice(routepy.extract_route_edges_from_file(ROUTE_FILENAME))
                        lane_pos = 1

            ADDED_UPDATED_VEHICLE_ID_EDGE[vehicle_id] = edge_id
            try:
                temp_route_id = f"temp_route_{vehicle_id}_{int(time.time()*1000)}"
                traci.route.add(temp_route_id, [edge_id])
                traci.vehicle.add(vehID=vehicle_id, routeID=temp_route_id, typeID="myType", departPos=lane_pos, departSpeed=0)
                traci.vehicle.setLength(vehicle_id, 10.0)
                traci.vehicletype.setMaxSpeed("myType", 50.0)
                traci.vehicletype.setAccel("myType", 5.0)
                traci.vehicletype.setDecel("myType", 9.0)
                traci.vehicletype.setTau("myType", 1.0)
                traci.vehicle.setColor(typeID=vehicle_id, color=(255, 0, 0, 255))
                traci.vehicle.setShapeClass(typeID=vehicle_id, shapeClass="truck")
                traci.vehicle.setSpeed(vehicle_id, 0)
                traci.vehicle.setLaneChangeMode(vehicle_id, 0x5ff)

                if vehicle_task_check(vehicle_id, need_add_task[vehicle_id], simulation_time, configs) == True:
                    set_vehicle_route_and_stop(vehicle_id, need_add_task[vehicle_id], configs)
                    traci.vehicle.setSpeed(vehicle_id, -1)
                    logger.info(f"新添加车辆 {vehicle_id} 并设置任务完成。")

            except traci.exceptions.TraCIException as e:
                logger.info(f"添加车辆 {vehicle_id} 失败: {e}。尝试直接设置其作业任务。")
                logger.info(traceback.format_exc())


    if len(need_update_task) > 0:
        logger.info(f"更新集卡任务")
        vehicle_update_positions_coord = {}
        for vehicle_id in need_update_task.keys():
            # #任务更新的车子先取消订阅。
            # if vehicle_id not in TRUCK_UNSUBSCRIBED_SET:
            #     traci.vehicle.unsubscribe(vehicle_id)

            if vehicle_id in VEHICLE_TO_STOP_COORD:
                APPEND_STOP_LIST.append(VEHICLE_TO_STOP_COORD[vehicle_id])
                del VEHICLE_TO_STOP_COORD[vehicle_id]
            try:
                edge_id = traci.vehicle.getRoadID(vehicle_id)
                lane_pos = traci.vehicle.getLanePosition(vehicle_id)
                route_edges_update_vehicle = traci.vehicle.getRoute(vehicle_id)

                if edge_id is not None and lane_pos is not None and edge_id != "":
                    if ":" in edge_id:
                        prev_edge,next_edge = routepy.find_previous_and_next_edges(route_edges_update_vehicle, edge_id)
                        edge_id = prev_edge
                        lane_pos = 1
                        ADDED_UPDATED_VEHICLE_ID_EDGE[vehicle_id] = edge_id
                        vehicle_update_positions_coord[vehicle_id] = (edge_id, lane_pos)
                    elif ":" not in edge_id:
                        ADDED_UPDATED_VEHICLE_ID_EDGE[vehicle_id] = edge_id
                        vehicle_update_positions_coord[vehicle_id] = (edge_id, lane_pos)

                elif edge_id is None or lane_pos is None or edge_id == "":
                    random_truck_start_list = random.choice(TRUCK_START_LIST)
                    x, y = random_truck_start_list
                    edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
                    if edge_id is None or lane_pos is None or edge_id == "":
                        random_truck_start_list = random.choice(TRUCK_START_LIST)
                        x, y = random_truck_start_list
                        edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
                        if edge_id is None or lane_pos is None or edge_id == "":
                            edge_id = random.choice(routepy.extract_route_edges_from_file(ROUTE_FILENAME))
                            lane_pos = 2

                    ADDED_UPDATED_VEHICLE_ID_EDGE[vehicle_id] = edge_id
                    vehicle_update_positions_coord[vehicle_id] = (edge_id, lane_pos)

            except traci.exceptions.TraCIException as e:
                logger.info(f"获取车辆 {vehicle_id} 的位置失败: {e}")
                logger.info(traceback.format_exc())
                return False, f"{vehicle_id}车辆任务更新过早，集卡车未在仿真中加载。"
            try:
                traci.vehicle.remove(vehicle_id)  # 删除当前车子
            except traci.exceptions.TraCIException as e:
                logger.info(f"删除车辆 {vehicle_id} 失败: {e}")
                logger.info(traceback.format_exc())

            edge_id, lane_pos = vehicle_update_positions_coord[vehicle_id]
            try:
                temp_route_id = f"temp_route_{vehicle_id}_{int(time.time()*1000)}"
                traci.route.add(temp_route_id, [edge_id])
                traci.vehicle.add(vehID=vehicle_id, routeID=temp_route_id, typeID="myType", departPos=lane_pos, departSpeed=0)
                traci.vehicle.setLength(vehicle_id, 10.0)
                traci.vehicletype.setMaxSpeed("myType", 50.0)
                traci.vehicletype.setAccel("myType", 5.0)
                traci.vehicletype.setDecel("myType", 9.0)
                traci.vehicletype.setTau("myType", 1.0)
                traci.vehicle.setColor(typeID=vehicle_id, color=(255, 0, 0, 255))
                traci.vehicle.setShapeClass(typeID=vehicle_id, shapeClass="truck")
                traci.vehicle.setSpeed(vehicle_id, 0)
                traci.vehicle.setLaneChangeMode(vehicle_id, 0x5ff)

                if vehicle_task_check(vehicle_id, need_update_task[vehicle_id], simulation_time, configs) == True:
                    set_vehicle_route_and_stop(vehicle_id, need_update_task[vehicle_id], configs)
                    traci.vehicle.setSpeed(vehicle_id, -1)
                    logger.info(f"集卡{vehicle_id}任务更新完成。")

            except traci.exceptions.TraCIException as e:
                logger.info(f"集卡{vehicle_id} 任务更新失败: {e}。尝试直接设置其作业任务。")  # 待优化
                logger.info(traceback.format_exc())

    # 删除没有作业任务的车辆 ——注释的原因是，让该车驶离作业点，防止卡住
    # rest_tasks = last_tasks - current_tasks  # 待优化
    # if len(rest_tasks)>0:
    #     for vehicle_id in rest_tasks:
    #         append_rest_stop_to_vehicle(vehicle_id, ROUTE_FILENAME)


def process_vehicle_data(vehicle_id, simulation_time, SIMULATION_START, vehicle_task_data, truck_info4update, all_tk_data, subscription_results):
    global TRUCK_UNSUBSCRIBED_SET
    # 从订阅结果中获取数据
    current_pos = subscription_results[vehicle_id][tc.VAR_POSITION]
    task_id = vehicle_task_data.get("task_id", "")
    angle = subscription_results[vehicle_id][tc.VAR_ANGLE]
    speed = subscription_results[vehicle_id][tc.VAR_SPEED]
    road_id = subscription_results[vehicle_id][tc.VAR_ROAD_ID]
    lane_index = subscription_results[vehicle_id][tc.VAR_LANE_INDEX]
    depart_lane = subscription_results[vehicle_id][tc.VAR_LANE_ID]
    depart_pos = subscription_results[vehicle_id][tc.VAR_LANEPOSITION]
    truck_stops = traci.vehicle.getStops(vehicle_id)

    # 获取路线（无法通过订阅获取，仍然需要调用 traci 方法）
    vehicle_route_edges = " ".join(traci.vehicle.getRoute(vehicle_id))

    # 程序逻辑：stop_exist 默认为 1
    # 在原有作业点上增加一个停车区停车点
    # 获取最后一个停车点，并判断车辆是否到达
    # 到达后，发出最后一次坐标，然后不再发送坐标
    stop_num = len(traci.vehicle.getStops(vehicle_id))
    stop_exist = 1

    if stop_num == 1:
        stops = traci.vehicle.getStops(vehicle_id)
        stop = stops[0]
        current_lane_pos = subscription_results[vehicle_id][tc.VAR_LANEPOSITION]
        current_lane = subscription_results[vehicle_id][tc.VAR_LANE_ID]
        TOLERANCE = 1.5
        if (current_lane == stop.lane and stop.startPos - TOLERANCE <= current_lane_pos <= stop.endPos + TOLERANCE and traci.vehicle.isStopped(vehicle_id)):
            stop_exist = 0

    vehicle_tk_data = {
        "truck_id": vehicle_id,
        "task_id": task_id,
        "simulation_start": SIMULATION_START,
        "simulation_time": simulation_time,
        "current_pos": current_pos,
        "angle": (angle - 90) % 360,
        "stop_exist": stop_exist
    }

    all_tk_data[vehicle_id] = vehicle_tk_data

    truck_info4update[vehicle_id] = {
        "depart_lane": depart_lane,
        "depart_pos": depart_pos,
        "depart_speed": speed,
        "vehicle_route_edges": vehicle_route_edges,
        "truck_stops": truck_stops,
        "route_edges": road_id
    }

    if stop_exist == 0:
        traci.vehicle.unsubscribe(vehicle_id)
        TRUCK_UNSUBSCRIBED_SET.add(vehicle_id)
        logger.info(f"{vehicle_id}作业完成，状态是{stop_exist}，坐标为：{current_pos}，已取消订阅。")
    # else:
    #     # logger.info(f"{vehicle_id}作业未完成，状态是1，坐标为：{current_pos}")


def run_netconvert(net_filename, configs):
    """
    使用 netconvert 运行并保存路网文件。
    """
    netconvert_command = [
        configs.netConvert,
        "--sumo-net-file",
        net_filename,
        "-o",
        net_filename,
        "--no-warnings", "true"
    ]
    subprocess.run(netconvert_command, check=True)


def vehicle_reset_route_stop_after_restart_simulation(current_edge, vehicle_id, configs, depart_pos):
    global APPEND_STOP_LIST, VEHICLE_TO_STOP_COORD, TRUCK_SUBSCRIBED_SET, TRUCK_UNSUBSCRIBED_SET
    temp_route_id = f"temp_route_{vehicle_id}_{int(time.time() * 1000)}"
    traci.route.add(temp_route_id, [current_edge])
    traci.vehicle.add(vehID=vehicle_id, routeID=temp_route_id, typeID="myType", departPos=depart_pos, departSpeed=0)
    traci.vehicle.setLength(vehicle_id, 10.0)
    traci.vehicletype.setMaxSpeed("myType", 50.0)
    traci.vehicletype.setAccel("myType", 5.0)
    traci.vehicletype.setDecel("myType", 9.0)
    traci.vehicletype.setTau("myType", 1.0)
    traci.vehicle.setColor(typeID=vehicle_id, color=(255, 0, 0, 255))
    traci.vehicle.setShapeClass(typeID=vehicle_id, shapeClass="truck")
    traci.vehicle.setSpeed(vehicle_id, 0)
    traci.vehicle.setLaneChangeMode(vehicle_id, 0x5ff)

    #测试
    APPEND_STOP_LIST = routepy.get_all_rest_stop_coordinates(configs.BASE_NET_FILE, configs.truck_stop_type,
                                                             configs.TRUCK_STOP_TIME)
    if vehicle_id in VEHICLE_TO_STOP_COORD:
        APPEND_STOP_LIST.append(VEHICLE_TO_STOP_COORD[vehicle_id])
        del VEHICLE_TO_STOP_COORD[vehicle_id]

    random_stop_temp = random.choice(APPEND_STOP_LIST)
    APPEND_STOP_LIST.remove(random_stop_temp)
    VEHICLE_TO_STOP_COORD[vehicle_id] = random_stop_temp
    rest_stop_edge = random_stop_temp['lane'][:-2]
    lane_index = 0
    lane_pos = 3
    rest_route = traci.simulation.findRoute(current_edge, rest_stop_edge)
    traci.vehicle.setRoute(vehicle_id, rest_route.edges)
    if lane_pos < depart_pos:
        lane_pos = depart_pos
    # traci.vehicle.setStop(vehID=vehicle_id, edgeID=rest_stop_edge, laneIndex=lane_index, pos=lane_pos,
    #                       duration=configs.TRUCK_STOP_TIME)
    try:
        traci.vehicle.setStop(vehID=vehicle_id, edgeID=rest_stop_edge, laneIndex=lane_index, pos=lane_pos,
                              duration=configs.TRUCK_STOP_TIME)
    except Exception:
        lane_pos =1.5
        traci.vehicle.setStop(vehID=vehicle_id, edgeID=rest_stop_edge, laneIndex=lane_index, pos=lane_pos,
                              duration=configs.TRUCK_STOP_TIME)
    traci.vehicle.setSpeed(vehicle_id, -1)

    if vehicle_id not in TRUCK_UNSUBSCRIBED_SET:
        traci.vehicle.subscribe(vehicle_id, [
            tc.VAR_POSITION,
            tc.VAR_ANGLE,
            tc.VAR_SPEED,
            tc.VAR_ROAD_ID,
            tc.VAR_LANE_INDEX,
            tc.VAR_LANE_ID,
            tc.VAR_LANEPOSITION
        ])
        TRUCK_SUBSCRIBED_SET.add(vehicle_id)


def vehicle_load_after_restart_simulation(configs, truck_info4update, task_data, vessel_data_LAST):
    global TRUCK_SUBSCRIBED_SET, TRUCK_UNSUBSCRIBED_SET,VESSEL2LANE
    if vessel_data_LAST is None or len(vessel_data_LAST) ==0:
        json_vessel_data = configs.redis_conn.get("vessel_data")
        vessel_data = json.loads(json_vessel_data)
        vessel_data_LAST = vessel_data
    vehicle_ids = task_data.keys()

    current_vessel_id_list = []
    for vessel_id in vessel_data_LAST:
        current_vessel_id_list.append(VESSEL2LANE[vessel_id]["s1_1Ts1_2"]["edge_id"])
    for vessel_id in vessel_data_LAST:
        current_vessel_id_list.append(VESSEL2LANE[vessel_id]["s2_1Ts2_2"]["edge_id"])

    # logger.info(f"vehicle_id 正在加载...{len(truck_info4update.keys())}")

    # success_count = 0
    for vehicle_id in vehicle_ids:
        if vehicle_id not in truck_info4update:
            logger.warning(f"警告：vehicle_id {vehicle_id} 在 truck_info4update 中不存在，跳过")
            #待优化
            continue
        truck_info = truck_info4update[vehicle_id]
        vehicle_route_edges = truck_info["vehicle_route_edges"]  # 完整路径（字符串）
        road_id = truck_info["route_edges"]  # 当前路段
        depart_pos = truck_info["depart_pos"]  # 出发位置
        route_edges_list = vehicle_route_edges.split(" ")
        truck_stops = truck_info["truck_stops"]
        if depart_pos is None:
            depart_pos = 2

        if ":" in road_id:
            prev_edge, next_edge = routepy.find_previous_and_next_edges(route_edges_list, road_id)
            road_id = prev_edge
            depart_pos = 1

            try:
                current_index = route_edges_list.index(road_id)
            except ValueError:
                continue

            stop_indices = []
            for stop in truck_stops:
                lane_id = stop.lane
                edge_id = lane_id.split("_")[0]
                try:
                    stop_index = route_edges_list.index(edge_id)
                    stop_indices.append(stop_index)
                except ValueError:
                    continue

            if current_index in stop_indices:
                if current_index > 0:
                    current_index -= 1
                else:
                    logger.warning(f"警告：vehicle_id {vehicle_id} 的 current_index 已经为0，不能减1，跳过")
                    continue

            remianing_route = route_edges_list[current_index:]
            if not any(edge in current_vessel_id_list for edge in remianing_route):
                current_edge = route_edges_list[current_index]
                logger.info(f"{vehicle_id} 的路径中不存在作业点，将驶去停车区。")
                vehicle_reset_route_stop_after_restart_simulation(current_edge, vehicle_id, configs, depart_pos)
                continue

            temp_route_id = f"route_{vehicle_id}_{int(traci.simulation.getTime())}"
            traci.route.add(temp_route_id, remianing_route)

            # 添加车辆
            traci.vehicle.add(vehID=vehicle_id, routeID=temp_route_id, typeID="myType", departPos=depart_pos, departSpeed="random")
            # success_count += 1
            traci.vehicle.setLength(vehicle_id, 10.0)
            traci.vehicletype.setMaxSpeed("myType", 50.0)
            traci.vehicletype.setAccel("myType", 5.0)
            traci.vehicletype.setDecel("myType", 9.0)
            traci.vehicletype.setTau("myType", 1.0)
            traci.vehicle.setColor(typeID=vehicle_id, color=(255, 0, 0, 255))
            traci.vehicle.setShapeClass(typeID=vehicle_id, shapeClass="truck")
            traci.vehicle.setLaneChangeMode(vehicle_id, 0x5ff)

            # 设置停车点
            for stop in truck_stops:
                lane_id = stop.lane
                lane_index = int(lane_id.rsplit("_", 1)[-1])
                edge_id = lane_id.split("_")[0]
                try:
                    stop_index = route_edges_list.index(edge_id)
                    if stop_index > current_index:
                        lane_pos = stop.startPos
                        try:
                            traci.vehicle.setStop(vehID=vehicle_id, edgeID=edge_id, laneIndex=lane_index, pos=lane_pos, duration=stop.duration)
                        except Exception:
                            lane_pos = 2
                            traci.vehicle.setStop(vehID=vehicle_id, edgeID=edge_id, laneIndex=lane_index, pos=lane_pos, duration=stop.duration)
                except ValueError:
                    continue

        elif ":" not in road_id:
            try:
                current_index = route_edges_list.index(road_id)
            except ValueError:
                continue

            # 获取所有 stop_index
            stop_indices = []
            for stop in truck_stops:
                lane_id = stop.lane
                edge_id = lane_id.split("_")[0]
                try:
                    stop_index = route_edges_list.index(edge_id)
                    stop_indices.append(stop_index)
                except ValueError:
                    continue

            # 检查是否有 stop_index 等于 current_index
            if current_index in stop_indices:
                if current_index > 0:
                    current_index -= 1
                else:
                    logger.warning(f"警告：vehicle_id {vehicle_id} 的 current_index 已经为0，不能减1，跳过")
                    continue

            remianing_route = route_edges_list[current_index:]
            if not any(edge in current_vessel_id_list for edge in remianing_route):
                current_edge = route_edges_list[current_index]
                logger.info(f"{vehicle_id} 的路径中不存在作业点，将驶去停车区。")
                vehicle_reset_route_stop_after_restart_simulation(current_edge, vehicle_id, configs, depart_pos)
                continue

            temp_route_id = f"route_{vehicle_id}_{int(traci.simulation.getTime())}"
            traci.route.add(temp_route_id, remianing_route)

            # 添加车辆
            traci.vehicle.add(vehID=vehicle_id, routeID=temp_route_id, typeID="myType", departPos=depart_pos, departSpeed="random")
            # success_count += 1
            traci.vehicle.setLength(vehicle_id, 10.0)
            traci.vehicletype.setMaxSpeed("myType", 50.0)
            traci.vehicletype.setAccel("myType", 5.0)
            traci.vehicletype.setDecel("myType", 9.0)
            traci.vehicletype.setTau("myType", 1.0)
            traci.vehicle.setColor(typeID=vehicle_id, color=(255, 0, 0, 255))
            traci.vehicle.setShapeClass(typeID=vehicle_id, shapeClass="truck")
            traci.vehicle.setLaneChangeMode(vehicle_id, 0x5ff)

            # 设置停车点
            for stop in truck_stops:
                lane_id = stop.lane
                lane_index = int(lane_id.rsplit("_", 1)[-1])
                edge_id = lane_id.split("_")[0]
                try:
                    stop_index = route_edges_list.index(edge_id)
                    if stop_index > current_index:
                        lane_pos = stop.startPos
                        try:
                            traci.vehicle.setStop(vehID=vehicle_id, edgeID=edge_id, laneIndex=lane_index, pos=lane_pos, duration=stop.duration)
                        except Exception:
                            lane_pos = 2
                            traci.vehicle.setStop(vehID=vehicle_id, edgeID=edge_id, laneIndex=lane_index, pos=lane_pos, duration=stop.duration)
                except ValueError:
                    continue

        if vehicle_id not in TRUCK_UNSUBSCRIBED_SET:
            traci.vehicle.subscribe(vehicle_id, [
                tc.VAR_POSITION,
                tc.VAR_ANGLE,
                tc.VAR_SPEED,
                tc.VAR_ROAD_ID,
                tc.VAR_LANE_INDEX,
                tc.VAR_LANE_ID,
                tc.VAR_LANEPOSITION
            ])
            TRUCK_SUBSCRIBED_SET.add(vehicle_id)
    # logger.info(f"成功加载{success_count}")


def simulation_step(SIMULATION_START, NET_FILENAME_BACKUPS, configs):
    global VESSEL2LANE, TRUCK_UNSUBSCRIBED_SET, TRUCK_START_LIST, ADDED_UPDATED_VEHICLE_ID_EDGE,TRUCK_SUBSCRIBED_SET,ROUTE_FILENAME,APPEND_STOP_LIST,ADDED_RANGES,ADDED_JUNCTIONS
    logger.info("开始码头集卡装卸作业路径仿真...")
    i = 0
    j = 0
    LAST_task_data = ''
    LAST_vessel_data = ''
    # traci.simulationStep()
    while True:
        try:
            start_time = datetime.now()  #  控制坐标输出时间
            target_time = start_time + timedelta(seconds=1)

            traci.simulationStep()
            simulation_time = traci.simulation.getTime()
            truck_info4update = {}
            all_tk_data = {}
            vessel_data_LAST = {}  #  上一帧的货船数据
            json_trucks = configs.redis_conn.hgetall("task_data")
            task_data = {key.decode(): json.loads(value) for key, value in json_trucks.items()}

            subscription_results = traci.vehicle.getAllSubscriptionResults()
            # logger.critical(f'首次仿真时subscription_results的结果{len(subscription_results)}')
            # logger.critical(f'首次仿真时subscription_results的结果{subscription_results}')

            for vehicle_id in subscription_results.keys():
                vehicle_task_data = task_data.get(vehicle_id, '')
                omitted_condition1 = vehicle_id in TRUCK_UNSUBSCRIBED_SET
                if omitted_condition1:
                    continue

                process_vehicle_data(vehicle_id, simulation_time, SIMULATION_START, vehicle_task_data, truck_info4update, all_tk_data, subscription_results)

            tk_data = {vehicle_id: json.dumps(tk_data) for vehicle_id, tk_data in all_tk_data.items()}
            while True:
                current_time = datetime.now()
                if (current_time - target_time).total_seconds() >= -0.005 or current_time >= target_time:
                    break
                time.sleep(0.0001)

            redis_task_data_manager(tk_data, configs, vehicle_id=None) #向孪生发送坐标。

            json_trucks = configs.redis_conn.hgetall("task_data")
            task_data = {key.decode(): json.loads(value) for key, value in json_trucks.items()}

            if i == 0:
                LAST_task_data = copy.deepcopy(task_data)
                logger.critical(f"标志1：初始化集卡任务！")
                for vehicle_id, task_info in task_data.items():
                    if vehicle_task_check(vehicle_id, task_data[vehicle_id], simulation_time, configs) == True:
                        set_vehicle_route_and_stop(vehicle_id, task_info, configs)
                i += 1
            else:
                cur_sumo_tk_id = traci.vehicle.getLoadedIDList()

                need_add_task = {}
                need_update_task = {}
                for tk_id,task in task_data.items():
                    if tk_id not in cur_sumo_tk_id:
                        need_add_task[tk_id] = task
                    else:
                        old_task = LAST_task_data.get(tk_id)
                        if old_task is None:
                            need_update_task[tk_id] = task
                        else:
                            if task['task_id'] != old_task['task_id']:
                                need_update_task[tk_id] = task

                if len(need_add_task) > 0 or len(need_update_task) > 0:
                    update_vehicle_tasks(need_update_task, need_add_task, simulation_time, configs)
                    LAST_task_data = copy.deepcopy(task_data)

            json_vessel_data = configs.redis_conn.get("vessel_data")
            vessel_data = json.loads(json_vessel_data)
            #把vessel_data中的所有key进行编码。待优化。

            if j == 0:
                LAST_vessel_data = copy.deepcopy(vessel_data)
                j += 1
                continue
            else:
                old_keys = set(LAST_vessel_data.keys())
                new_keys = set(vessel_data.keys())
                vessel_data_LAST = vessel_data
                if (len(new_keys) > len(old_keys)) or (len(old_keys) == len(new_keys) and new_keys != old_keys):
                    NET_FILENAME_BEFORE_UPDATE = NET_FILENAME_BACKUPS
                    TRUCK_SUBSCRIBED_SET.clear()
                    ADDED_RANGES.clear()
                    ADDED_JUNCTIONS.clear()
                    VESSEL2LANE.clear()
                    try:
                        traci.close()
                        NET_FILENAME_UPDATE, NET_FILENAME_BACKUPS = initialize_netxml(vessel_data, configs)
                        NET_FILENAME = NET_FILENAME_UPDATE
                        logger.warning(f'添加船舶并升级路网为{os.path.basename(NET_FILENAME_UPDATE)}')

                        try:
                            run_netconvert(NET_FILENAME, configs)
                            print(f"路网文件{os.path.basename(NET_FILENAME_UPDATE)}处理成功，继续使用更新后的文件。")
                        except subprocess.CalledProcessError:
                            vessel_info = "; ".join(
                                f"{vessel_id}, \"head_x\": {data['head_x']}, \"tail_x\": {data['tail_x']}"
                                for vessel_id, data in vessel_data.items()
                            )
                            logger.critical(f"处理路网文件{os.path.basename(NET_FILENAME_UPDATE)}时发生错误，使用旧路网文件。"
                                            f"当前任务批次的船舶信息如下：{vessel_info}")
                            NET_FILENAME = NET_FILENAME_BEFORE_UPDATE

                        # ROUTE_FILENAME = routepy.update_rouxml_with_netxml(truck_info4update, NET_FILENAME, VESSEL2LANE_BEFORE_UPDATE, VESSEL2LANE, TRUCK_START_LIST, configs)
                        # print(f"更新后的路由文件是：{ROUTE_FILENAME}")
                        sumoCmd = [
                            configs.sumoBinary,
                            "--net-file", NET_FILENAME,
                            "--route-files", "type.rou.xml",
                            "--gui-settings-file", configs.gui_settings_file,
                            "--time-to-teleport", "15",
                            "--step-length", "1",
                            "--route-steps", "0",
                            "--no-warnings", "true"
                        ]

                        traci.start(sumoCmd)
                        SIMULATION_START = datetime.now().strftime("%Y%m%d-%H:%M:%S")
                        json_trucks = configs.redis_conn.hgetall("task_data")
                        task_data = {key.decode(): json.loads(value) for key, value in json_trucks.items()}

                        logger.info(f"重新加载上次仿真中集卡车的位置。")
                        vehicle_load_after_restart_simulation(configs, truck_info4update, task_data, vessel_data_LAST)

                        logger.critical(f"已重启仿真会话，使用新路网文件: {os.path.basename(NET_FILENAME)}")
                        LAST_vessel_data = copy.deepcopy(vessel_data)
                    except Exception as e:
                        logger.info(f"启动仿真时发生错误: {e}")
                        logger.info(traceback.format_exc())

                elif len(old_keys) > len(new_keys):
                    ADDED_RANGES.clear()
                    ADDED_JUNCTIONS.clear()
                    VESSEL2LANE.clear()
                    # NET_FILENAME_BEFORE_UPDATE = NET_FILENAME_BACKUPS
                    try:
                        # traci.close()
                        NET_FILENAME_UPDATE, NET_FILENAME_BACKUPS = initialize_netxml(vessel_data, configs)
                        # NET_FILENAME = NET_FILENAME_UPDATE
                        logger.warning(f'删除船舶并升级路网为{os.path.basename(NET_FILENAME_UPDATE)}')

                        # run_netconvert(NET_FILENAME, configs)
                        # print(f"路网文件{os.path.basename(NET_FILENAME_UPDATE)}处理成功，继续使用更新后的文件。")
                    except subprocess.CalledProcessError:
                        logger.info(f"处理路网文件{os.path.basename(NET_FILENAME_UPDATE)}时发生错误，使用旧路网文件。")
                        logger.info("当前任务批次的船舶信息如下：")
                        vessel_info = "; ".join(
                            f"{vessel_id}, \"head_x\": {data['head_x']}, \"tail_x\": {data['tail_x']}"
                            for vessel_id, data in vessel_data.items()
                        )
                        logger.info(f"{{{vessel_info}}}")
                        # NET_FILENAME = NET_FILENAME_BEFORE_UPDATE

                    # ROUTE_FILENAME = routepy.update_rouxml_with_netxml(truck_info4update, NET_FILENAME,
                    #                                                    VESSEL2LANE_BEFORE_UPDATE, VESSEL2LANE,
                    #                                                    TRUCK_START_LIST, configs)
                    # print(f"更新后的路由文件是：{ROUTE_FILENAME}")
                    # sumoCmd = [
                    #     configs.sumoBinary,
                    #     "--net-file", NET_FILENAME,
                    #     "--route-files", "type.rou.xml",
                    #     "--gui-settings-file", configs.gui_settings_file,
                    #     "--time-to-teleport", "15",
                    #     "--step-length", "1",
                    #     "--route-steps", "0",
                    #     "--no-warnings", "true"
                    # ]

                    # traci.start(sumoCmd)
                    # SIMULATION_START = datetime.now().strftime("%Y%m%d-%H:%M:%S")
                    # json_trucks = configs.redis_conn.hgetall("task_data")
                    # task_data = {key.decode(): json.loads(value) for key, value in json_trucks.items()}

                    # logger.info(f"重新加载上次仿真中集卡车的位置。")
                    # vehicle_load_after_restart_simulation(configs, truck_info4update, task_data, vessel_data_LAST)

                    # logger.critical(f"已重启仿真会话，使用新路网文件: {os.path.basename(NET_FILENAME)}")
                    LAST_vessel_data = copy.deepcopy(vessel_data)

        except Exception as e:
            logger.info(f"发生错误，重置仿真会话...{e}")
            logger.info(traceback.format_exc())
            VESSEL2LANE.clear()
            ADDED_RANGES.clear()
            ADDED_JUNCTIONS.clear()
            ADDED_UPDATED_VEHICLE_ID_EDGE.clear()
            TRUCK_UNSUBSCRIBED_SET.clear()
            TRUCK_SUBSCRIBED_SET.clear()
            APPEND_STOP_LIST = ""
            TRUCK_START_LIST = ""
            ROUTE_FILENAME = ''
            if traci.isLoaded():
                traci.close()
            json_vessel_data = configs.redis_conn.get("vessel_data")
            vessel_data = json.loads(json_vessel_data)
            task_data_json = configs.redis_conn.hgetall("task_data")
            task_data = {key.decode(): json.loads(value) for key, value in task_data_json.items()}

            if len(vessel_data) == 0 or len(task_data) == 0:
                logger.warning("没有货船数据，请等待...")
                time.sleep(10)
                continue

            NET_FILENAME, NET_FILENAME_BACKUPS = initialize_netxml(vessel_data, configs)

            try:
                run_netconvert(NET_FILENAME, configs)
                print(f"路网文件{os.path.basename(NET_FILENAME)}处理成功，继续使用更新后的文件。")
            except subprocess.CalledProcessError:
                logger.info(f"处理路网文件{os.path.basename(NET_FILENAME)}时发生错误。")
                logger.info("当前任务批次的船舶信息如下：")
                vessel_info = "; ".join(
                    f"{vessel_id}, \"head_x\": {data['head_x']}, \"tail_x\": {data['tail_x']}"
                    for vessel_id, data in vessel_data.items()
                )
                logger.info(f"{{{vessel_info}}}")

            # ROUTE_FILENAME = routepy.update_rouxml_with_netxml(truck_info4update, NET_FILENAME, VESSEL2LANE_BEFORE_UPDATE, VESSEL2LANE, TRUCK_START_LIST, configs)
            # print(f"更新后的路由文件是：{ROUTE_FILENAME}")
            sumoCmd = [
                configs.sumoBinary,
                "--net-file", NET_FILENAME,
                "--route-files", "type.rou.xml",
                "--gui-settings-file", configs.gui_settings_file,
                "--time-to-teleport", "15",
                "--step-length", "1",
                "--route-steps", "0",
                "--no-warnings", "true",
                "--ignore-route-errors", "true"
            ]
            traci.start(sumoCmd)
            SIMULATION_START = datetime.now().strftime("%Y%m%d-%H:%M:%S")

            logger.info(f"重新加载上次仿真中集卡车的位置。")
            vehicle_load_after_restart_simulation(configs, truck_info4update, task_data, vessel_data_LAST)


def run(configs):
    global ROUTE_FILENAME, APPEND_STOP_LIST, TRUCK_START_LIST,ADDED_UPDATED_VEHICLE_ID_EDGE,TRUCK_SUBSCRIBED_SET,TRUCK_UNSUBSCRIBED_SET
    ADDED_UPDATED_VEHICLE_ID_EDGE.clear()
    TRUCK_UNSUBSCRIBED_SET.clear()
    TRUCK_SUBSCRIBED_SET.clear()
    APPEND_STOP_LIST = ""
    TRUCK_START_LIST = ""
    ROUTE_FILENAME = ''

    json_vessel_data = configs.redis_conn.get("vessel_data")
    vessel_data = json.loads(json_vessel_data)
    task_data_json = configs.redis_conn.hgetall("task_data")
    task_data = {key.decode(): json.loads(value) for key, value in task_data_json.items()}

    if len(vessel_data) == 0 or len(task_data) == 0:
        logger.warning("没有货船数据，请等待...")
        time.sleep(10)
        return

    NET_FILENAME, NET_FILENAME_BACKUPS = initialize_netxml(vessel_data, configs)

    logger.info(f'初始有({len(vessel_data)})货船、({len(task_data)})集卡数据，路网文件初始化成功。')
    run_netconvert(NET_FILENAME, configs)   # 返回Success

    TRUCK_START_LIST = routepy.get_all_car_start_coordinates(configs.BASE_NET_FILE, configs.truck_start_type)
    APPEND_STOP_LIST = routepy.get_all_rest_stop_coordinates(configs.BASE_NET_FILE, configs.truck_stop_type,
                                                             configs.TRUCK_STOP_TIME)
    buffer_rest_stop_coordinates = routepy.get_Buffer_area_rest_stop_coordinates(NET_FILENAME,
                                                                                  configs.truck_buffer_stop_type,
                                                                                  configs.TRUCK_STOP_TIME)
    APPEND_STOP_LIST.extend(buffer_rest_stop_coordinates)


    if task_data:
        ROUTE_FILENAME = routepy.initialize_rouxml(configs.BASE_NET_FILE, task_data, TRUCK_START_LIST,
                                                   configs.BATCH_SIZE, configs.INTERVAL)
    else:
        logger.info("集卡任务数据为空，无法生成集卡初始位置信息，请检查数据链路！！！！")
        return

    sumoCmd = [
        configs.sumoBinary,
        "--net-file", NET_FILENAME,
        "--route-files", ROUTE_FILENAME,
        "--gui-settings-file", configs.gui_settings_file,
        "--time-to-teleport", "15",
        "--step-length", "1",
        "--route-steps", "0",
        "--no-warnings", "true",
        "--ignore-route-errors", "true"
    ]
    traci.start(sumoCmd)

    simulation_step(configs.SIMULATION_START, NET_FILENAME_BACKUPS, configs)
